// Includes
#include "EventHandler.h"

#include <cstring>		// C string library

namespace EraAstral
{
	namespace core
	{
		// Event handler class constructor
		EventHandler::EventHandler()
		{
			// Set initial parameters for current event
			curEvent = new Event();
			curEvent->type = EVENT_NONE;
			curEvent->data = new char[8];
		}
		
		// Event handler class destructor
		EventHandler::~EventHandler()
		{
			// Free memory allocated for current event
			delete[] curEvent->data;
			delete curEvent;
		}
		
		// Processes all pending events
		void EventHandler::ProcessEvents()
		{
			// Temporary event struct
			SDL_Event sdlEvent;
			// Clear current event data
			memset(curEvent->data, 0, 8);
			
			// Pointers used for allocation of event data
			int *vr_ptr = 0;
			SDLKey *ke_ptr = 0;
			SDLMod *mod_ptr = 0;
			Uint16 *mm_ptr = 0;
			Uint8 *btn_ptr = 0;
			
			// Check for pending events
			while (SDL_PollEvent(&sdlEvent))
			{
				// Switch event type
				switch (sdlEvent.type)
				{
					// OpenGL window exposed
					case SDL_VIDEOEXPOSE:
						curEvent->type = EVENT_EXPOSE;
						break;
						
					// SDL quit event
					case SDL_QUIT:
						curEvent->type = EVENT_QUIT;
						break;
						
					// SDL resize event - OpenGL window resized
					case SDL_VIDEORESIZE:
						curEvent->type = EVENT_VIDEO_RESIZE;
						vr_ptr = (int *)curEvent->data;
						*vr_ptr = sdlEvent.resize.w;
						vr_ptr++;
						*vr_ptr = sdlEvent.resize.h;
						break;
						
					// Key pressed down
					case SDL_KEYDOWN:
						curEvent->type = EVENT_KEY_PRESS;
						ke_ptr = (SDLKey *)curEvent->data;
						*ke_ptr = sdlEvent.key.keysym.sym;
						mod_ptr = (SDLMod *)curEvent->data;
						mod_ptr++;
						*mod_ptr = sdlEvent.key.keysym.mod;
						break;
						
					// Key released
					case SDL_KEYUP:
						curEvent->type = EVENT_KEY_RELEASE;
						ke_ptr = (SDLKey *)curEvent->data;
						*ke_ptr = sdlEvent.key.keysym.sym;
						mod_ptr = (SDLMod *)curEvent->data;
						mod_ptr++;
						*mod_ptr = sdlEvent.key.keysym.mod;
						break;
						
					// Mouse movement
					case SDL_MOUSEMOTION:
						curEvent->type = EVENT_MOUSE_MOVE;
						mm_ptr = (Uint16 *)curEvent->data;
						*mm_ptr = sdlEvent.motion.x;
						mm_ptr++;
						*mm_ptr = sdlEvent.motion.y;
						break;
						
					// Mouse button pressed down
					case SDL_MOUSEBUTTONDOWN:
						curEvent->type = EVENT_BUTTON_PRESS;
						btn_ptr = (Uint8 *)curEvent->data;
						*btn_ptr = sdlEvent.button.button;
						break;
						
					// Mouse button released
					case SDL_MOUSEBUTTONUP:
						curEvent->type = EVENT_BUTTON_RELEASE;
						btn_ptr = (Uint8 *)curEvent->data;
						*btn_ptr = sdlEvent.button.button;
						break;
						
					// Unhandled event type
					default:
						break;
				}				
				
				// Send event signal to registered objects
				for (unsigned int i = 0; i < m_affectedObjects.size(); i++)
				{
					m_affectedObjects[i]->ProcessEventSignal(curEvent);
				}
			}
		}
			
		void EventHandler::RegisterAffectedObject(IHasEvents *object)
		{
			// Push object to vector
			m_affectedObjects.push_back(object);
		}
	}
}
